<?php

namespace Plugins\AdminBasic\Http\Admin\Service\UpdateCURDFiles;

use App\Enums\Attributes\DesAttribute;
use App\Enums\Attributes\TagAttribute;
use App\Enums\EnumTraits\EnumStatusTrait;
use Sc\Util\ClassFile\ClassFileResolve;
use Sc\Util\ClassFile\Components\Attribute;
use Sc\Util\ClassFile\Components\ClassFileConstruction;
use Sc\Util\ClassFile\Components\Constant;

class UpdateEnum
{

    private bool $isNew;
    private array $enumTheme;

    public function __construct(
        private string $fullEnumName,
        private string $enumPath,
        private array $field,
        private array $translationRes,
    ){
        $this->isNew = !enum_exists($this->fullEnumName);
        $this->enumTheme = $this->getEnumTheme();
    }

    public function update(string $tableComment): string
    {
        if ($this->isNew) {
            return $this->new($tableComment);
        }

        $enum = ClassFileResolve::resolve($this->fullEnumName);
        $hasConstant = [];
        foreach ($enum->getConstants() as $constant) {
            $hasConstant[$constant->getValue()] = $constant;
        }

        $isUpdate = false;
        foreach ($this->field['status_map'] as $value) {
            if (!isset($hasConstant[$value['key']])){
                $enum->addConstants($this->newCase($value['value'], $value['key'], $enum));
                $isUpdate = true;
                continue;
            }
            next($this->enumTheme);
            $attribute = $hasConstant[$value['key']]->getAttribute($enum->getAppropriateClassName(DesAttribute::class));
            if ($value['value'] != $attribute->getParamValue()) {
                $attribute->setParam($value['value']);
                $isUpdate = true;
            }
        }
        if ($isUpdate){
            file_put_contents($this->enumPath, $enum->getCode());
        }

        return $isUpdate ? "枚举{$this->fullEnumName}更新成功" : "枚举{$this->fullEnumName}无需更新";
    }

    private function new(string $tableComment): string
    {
        $classnameArr = explode('\\', $this->fullEnumName);
        $enum = new ClassFileConstruction(end($classnameArr));
        array_pop($classnameArr);
        $enum->setNamespace(implode('\\', $classnameArr));
        $enum->setIsEnum(true);
        $enum->setEnumBackedType('int');
        $enum->addUses(DesAttribute::class);
        $enum->addUses(TagAttribute::class);
        $enum->addUses(EnumStatusTrait::class);
        $enum->addTraits(EnumStatusTrait::class);
        $enum->setDocBlock($tableComment . ': ' . $this->field['comment']);

        $this->makeCases($this->field['status_map'], $enum);

        file_put_contents($this->enumPath, $enum->getCode());

        return "枚举{$this->fullEnumName}创建成功";
    }

    /**
     * 枚举状态主题
     *
     * @return array
     */
    private function getEnumTheme(): array
    {
        $types  = ['', 'success', 'warning', 'danger', 'info', 'primary'];
        $themes = ['light', 'dark', 'plain'];

        $res = [];
        foreach ($themes as $theme) {
            foreach ($types as $type) {
                $res[] = [$type, $theme];
            }
        }

        return $res;
    }

    /**
     * @param                       $statusMap
     * @param ClassFileConstruction $enum
     *
     * @return void
     */
    private function makeCases($statusMap, ClassFileConstruction $enum): void
    {
        foreach ($statusMap as ['key' => $value, 'value' => $comment]) {
            $enum->addConstants($this->newCase($comment, $value, $enum));
        }
    }

    /**
     * @param mixed $comment
     * @param mixed $value
     * @param ClassFileConstruction $enum
     * @return Constant
     */
    function newCase(mixed $comment, mixed $value, ClassFileConstruction $enum): Constant
    {
        $constant = new Constant($this->translationRes[$comment]);
        $constant->setIsEnum(true);
        $constant->setValue((int)$value);
        $constant->setDocBlockComment($comment);

        $constant->addAttribute(function () use ($comment, $enum) {
            $attribute = new Attribute($enum->getAppropriateClassName(DesAttribute::class));
            $attribute->addParam($comment);
            return $attribute;
        });

        $constant->addAttribute(function () use (&$enumTheme, $enum) {
            $attribute = new Attribute($enum->getAppropriateClassName(TagAttribute::class));
            [$type, $theme] = next($this->enumTheme);
            $attribute->addParam($type);
            $attribute->addParam($theme);
            return $attribute;
        });

        return $constant;
    }
}
